package socket;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

/**
 *聊天室服务端
 */

public class Server {
    /**
     * java.net.ServerSocket
     * 运行在服务端的ServerSocket主要有两个作用
     * 1:监听服务端口，一旦一个客户端连接就会立即返回一个Socket，通过它与客户端
     * 进行双向交换
     *
     * 如果我们将Socket 比喻为"电话" 那么ServerSocket相当于“总机”
     *
     */
    private ServerSocket serverSocket;

    //构造方法
    public Server(){
        try {
            /*
            实例化ServerSocket时要指定服务端口，该端口不能与系统其他应用程序
            占用的端口相同，否则会抛出异常
            java.net.BindException：address already in use
            若出现异常，解决方法为更换端口.知道不抛异常。
             */
            System.out.println("正在启动服务端..");
            serverSocket = new ServerSocket(8088);
            System.out.println("服务端启动完毕！");
        } catch (IOException e) {
            e.printStackTrace();
          }

    }
    //启动方法
    public void start(){

        try {
            Socket socket = null;
            while (true) {
                System.out.println("等待客户端连接...");
            /*
            ServerSocket提供的方法
            Socket accept（）
            该方法是一个阻塞方法，调用后开始等待客户端的连接，一旦一个客户端
            连接那么该方法会立即返回一个Socket

            好比这个方法总机这边的接电话动作

             */
                socket = serverSocket.accept();
                System.out.println("一个客户端连接了");

                //启动一个线程来与该客户端交互
                ClientHandler handler = new ClientHandler(socket);
                Thread t= new Thread(handler);
                t.start();



            }

        } catch (IOException e) {
            e.printStackTrace();
          }

    }

      public static void main(String[] args) {
        Server server = new Server();
        server.start();
      }

    /**
     * 该线程任务用于与指定的客户端进行交互。
     *
     */
    private class ClientHandler implements Runnable{
        private Socket socket;
        private String host;  //客户端的地址信息

        public ClientHandler(Socket socket){
            this.socket = socket;
            //通过socket获取远端计算机地址信息
            host = socket.getInetAddress().getHostAddress();

        }

        public void run(){
            try{
                InputStream in = socket.getInputStream();
                InputStreamReader isr = new InputStreamReader(in);
                //缓冲流（高级流.字符流）。块读文本数据加速。按行读取字符串
                BufferedReader br = new BufferedReader(isr);

                String line;
            /*
            服务端通过缓冲流读取客户端发送来的一行字符串的操作时，这个方法
            会产生阻塞，等待对方发来信息，直到对方发送过来的一行字符串则该方法
            返回此行内容
            当客户端调用socket.close（）断开连接，那么这可里readline方法
            会放回null 表述流读取到了末尾（对方断开连接）
            如果客户端是意外中断（强行关闭客户端程序 停电 断网等）那么服务端这边
            readline方法会抛出异常
             */

                while ((line = br.readLine()) != null) {
                    System.out.println(host+"：" + line);
                }

            }catch (IOException e){
                e.printStackTrace();
            }

        }
    }

}
